package com.xlh.dokka.svc.core.novnc;

import com.jcraft.jsch.JSchException;
import com.xlh.dokka.svc.properties.NovncProperties;
import com.xlh.util.SpringContextUtil;
import com.xlh.util.SshUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

/**
 * novnc服务器与应用服务器不在一台物理机上时，使用ssh通讯
 *
 * @author cheer
 */
@Slf4j
public class RemoteNovncConnector extends AbstractNovncConnector implements NovncConnector {

    private final String writeTokenCommand;

    private final String deleteTokenCommand;

    private final String host;

    private final Integer port;

    private final String username;

    private final String password;

    private SshUtil sshUtil;

    private Boolean sshSuccess = false;

    private ReentrantLock lock = new ReentrantLock();

    public RemoteNovncConnector() {
        NovncProperties novncProperties = SpringContextUtil.getBean(NovncProperties.class);
        this.writeTokenCommand = "echo %s: %s > " + novncProperties.getDir() + "/utils/websockify/token/%s";
        this.deleteTokenCommand = "rm -f " + novncProperties.getDir() + "/utils/websockify/token/%s";
        this.prefix = novncProperties.getPrefix();
        this.host = novncProperties.getSshHost();
        this.port = novncProperties.getSshPort();
        this.username = novncProperties.getSshUsername();
        this.password = novncProperties.getSshPassword();
    }

    @Override
    protected Boolean writeToken(Long dokkaId, String vnc) {
        lock.lock();
        try {
            if (checkSshUtil()) {
                String tokenKey = prefix + dokkaId;
                String command = String.format(writeTokenCommand, tokenKey, vnc, tokenKey);
                try {
                    sshUtil.execWithoutReturn(command);
                    return true;
                } catch (JSchException e) {
                    log.error("novnc write {} token failed", tokenKey, e);
                }
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void initialize() {
        lock.lock();
        try {
            checkSshUtil();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void deleteToken(Long dokkaId) {
        lock.lock();
        try {
            if (checkSshUtil()) {
                String tokenKey = prefix + dokkaId;
                String command = String.format(deleteTokenCommand, tokenKey);
                try {
                    sshUtil.execWithoutReturn(command);
                } catch (JSchException e) {
                    log.error("novnc delete {} token failed", tokenKey, e);
                }
            }
        } finally {
            lock.unlock();
        }
    }

    private boolean checkSshUtil() {
        if (sshUtil != null && sshUtil.getSession().isConnected()) {
            return true;
        }

        if (sshSuccess) {
            sshSuccess = false;
            log.error("novnc host {} ssh disconnected", host);
        }

        sshUtil = SshUtil.newInstance(username, password, host, port);
        if (sshUtil.getSession().isConnected()) {
            if (!sshSuccess) {
                sshSuccess = true;
                log.info("novnc host {} ssh connected", host);
            }
            return true;
        }
        return false;
    }
}
